package com.yanyu.space.common.log.handler;

import com.yanyu.space.common.core.util.AppContext;
import com.yanyu.space.common.log.message.LogMessage;
import com.yanyu.space.common.log.message.pool.LogMessagePool;
import com.yanyu.space.common.log.sender.LogSender;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.sleuth.TraceContext;
import org.springframework.cloud.sleuth.Tracer;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author yanyu
 */
@Slf4j
public class LogFactory {
    private static final Integer INIT_LOGPROCESSORS_LENGTH = 2;
    private static volatile LogFactory logTracer = new LogFactory();
    private Tracer tracer;
    private final List<LogWorker> logWorkers = new ArrayList<>();
    private final AtomicBoolean toStart = new AtomicBoolean(false);

    private LogFactory() {
    }

    public static LogFactory getInstance() {
        return logTracer;
    }

    /**
     * 开始日志记录
     */
    void init(Integer concurrency, Tracer tracer, Class<LogMessagePool> clazz) {
        if (this.toStart.compareAndSet(false, true)) {
            Integer newConcurrency = Optional.ofNullable(concurrency).orElse(INIT_LOGPROCESSORS_LENGTH);
            LogSender logSender = AppContext.getBean(LogSender.class);
            for (int i = 0; i < newConcurrency; i++) {
                LogWorker worker = new LogWorker(i, logSender, clazz);
                logWorkers.add(worker);
            }
            this.tracer = tracer;
        }
    }

    /**
     * 初始化
     *
     * @param traceContext
     */
    public LogWorkerContext start(TraceContext traceContext) {
        return this.start(traceContext.traceId());
    }

    /**
     * 初始化
     *
     * @param traceId
     */
    public LogWorkerContext start(String traceId) {
        if (toStart.get()) {
            LogWorkerContext logWorkerContext = LogWorkerContextHolder.get();
            if (logWorkerContext != null) {
                logWorkerContext.incAndGet();
            } else {
                LogWorker logWorker = getMinSizeLogWorker();
                logWorkerContext = new LogWorkerContext(traceId, logWorker);
                LogWorkerContextHolder.set(logWorkerContext);
            }

            return logWorkerContext;
        }
        return new LogWorkerContext();
    }

    /**
     * 提交日志
     *
     * @param logMessage
     */
    public void submit(LogMessage logMessage) {
        if (toStart.get()) {
            LogWorkerContext logWorkerContext = LogWorkerContextHolder.get();
            if (logWorkerContext != null) {
                logWorkerContext.getLogWorker().put(logWorkerContext.getTraceId(), logMessage);
            }
        }
    }

    /**
     * 关闭
     */
    public void close() {
        if (toStart.get()) {
            LogWorkerContext logWorkerContext = LogWorkerContextHolder.get();
            if (logWorkerContext != null && logWorkerContext.decAndGet() == 0) {
                logWorkerContext.getLogWorker().handle(logWorkerContext.getTraceId());
                LogWorkerContextHolder.remove();
            }
        }
    }

    /**
     * 获取worker
     *
     * @return
     */
     LogWorker getMinSizeLogWorker() {
        int minSize = Integer.MAX_VALUE;
        LogWorker minSizeLogWorker = null;
        for (LogWorker logWorker : logWorkers) {
            int curSize = logWorker.capacity();
            if (minSize > curSize) {
                minSizeLogWorker = logWorker;
                minSize = curSize;
            }
        }
        return minSizeLogWorker;
    }

}
